#pragma warning(disable : 4355)
#include "Avalon/IO/ChannelAdapterServerConnection.hpp"
#include "Avalon/IO/Channel.hpp"
#include "Avalon/IO/NotConnectedException.hpp"

using namespace Avalon;
using namespace Avalon::IO;
using namespace Avalon::Threading;
using namespace boost;
using namespace std;

ChannelAdapterServerConnection::ChannelAdapterServerConnection(
    ServerConnection* connection, ChannelFactory* channelFactory)
    : m_connection(connection),
      m_acceptSlot(bind(&ChannelAdapterServerConnection::OnAccept, this)),
      m_channelFactory(channelFactory) {}

ChannelAdapterServerConnection::~ChannelAdapterServerConnection() {
  Close();
}

void ChannelAdapterServerConnection::Open() {
  m_connection->Open();
}

void ChannelAdapterServerConnection::Accept(Out<Async<Channel*> > channel) {
  Async<Channel*>::State acceptState;
  m_result.SetFinishedSlot(m_acceptSlot, Store(acceptState));
  m_wrappedChannel = channel.Get();
  m_connection->Accept(Store(m_result));
}

bool ChannelAdapterServerConnection::IsOpen() const {
  return m_connection->IsOpen();
}

void ChannelAdapterServerConnection::Close() {
  m_connection->Close();
}

void ChannelAdapterServerConnection::SetClosedSlot(const ClosedSlot& slot,
    Out<bool> isOpen) {
  m_connection->SetClosedSlot(slot, Store(isOpen));
}

void ChannelAdapterServerConnection::OnAccept() {
  if(m_result.GetState() == Async<Channel*>::EXCEPTION) {
    exception_ptr exception = m_result.GetException();
    m_result.Reset();
    Async<Channel*>* wrappedChannel = m_wrappedChannel;
    m_wrappedChannel = NULL;
    wrappedChannel->SetException(exception);
  } else {
    Channel* channel = m_channelFactory->Create(m_result.Get());
    m_result.Reset();
    Async<Channel*>* wrappedChannel = m_wrappedChannel;
    m_wrappedChannel = NULL;
    wrappedChannel->SetResult(channel);
  }
}
